package com.jie.component.lock.util;

import com.jie.component.lock.core.LockType;
import com.jie.component.lock.factory.ServiceLockFactory;
import com.jie.component.lock.locker.ServiceLocker;
import com.jie.component.lock.lockinfo.LockInfoHandle;
import com.jie.component.lock.lockinfo.LockInfoType;
import com.jie.component.lock.lockinfo.factory.LockInfoHandleFactory;
import com.jie.component.lock.strategy.LockTimeOutStrategy;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;

import java.util.concurrent.TimeUnit;

/**
 * @author jie
 * @version 1.0 2025-02-09
 */
@Slf4j
@AllArgsConstructor
public class ServiceLockTool {

    private final LockInfoHandleFactory lockInfoHandleFactory;

    private final ServiceLockFactory serviceLockFactory;

    public void execute(TaskRun taskRun, String name) {
        execute(taskRun,name,new String[] {});
    }

    /**
     * 没有返回值的加锁执行
     *
     * @param taskRun 要执行的任务
     * @param name    锁的业务名
     * @param keys    锁的标识
     */
    public void execute(TaskRun taskRun, String name, String[] keys) {
        execute(taskRun, name, keys, 20);
    }

    /**
     * 没有返回值的加锁执行
     *
     * @param taskRun  要执行的任务
     * @param name     锁的业务名
     * @param keys     锁的标识
     * @param waitTime 等待时间
     */
    public void execute(TaskRun taskRun, String name, String[] keys, long waitTime) {
        execute(LockType.Reentrant, taskRun, name, keys, waitTime);
    }

    /**
     * 没有返回值的加锁执行
     *
     * @param lockType 锁类型
     * @param taskRun  要执行的任务
     * @param name     锁的业务名
     * @param keys     锁的标识
     */
    public void execute(LockType lockType, TaskRun taskRun, String name, String[] keys) {
        execute(lockType, taskRun, name, keys, 20);
    }

    /**
     * 没有返回值的加锁执行
     *
     * @param lockType 锁类型
     * @param taskRun  要执行的任务
     * @param name     锁的业务名
     * @param keys     锁的标识
     * @param waitTime 等待时间
     */
    public void execute(LockType lockType, TaskRun taskRun, String name, String[] keys, long waitTime) {
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name, keys);
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, waitTime);
        if (result) {
            try {
                taskRun.run();
            } finally {
                lock.unlock(lockName);
            }
        } else {
            LockTimeOutStrategy.FAIL.handler(lockName);
        }
    }

    /**
     * 有返回值的加锁执行
     *
     * @param taskCall 要执行的任务
     * @param name     锁的业务名
     * @param keys     锁的标识
     * @return 要执行的任务的返回值
     */
    public <T> T submit(TaskCall<T> taskCall, String name, String[] keys) {
        return submit(LockType.Reentrant, taskCall, name, keys);
    }

    public <T> T submit(LockType lockType, TaskCall<T> taskCall, String name, String[] keys) {
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name, keys);
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        boolean result = lock.tryLock(lockName, TimeUnit.SECONDS, 30);
        if (result) {
            try {
                return taskCall.call();
            } finally {
                lock.unlock(lockName);
            }
        } else {
            LockTimeOutStrategy.FAIL.handler(lockName);
        }
        return null;
    }

    /**
     * 获得锁
     *
     * @param lockType 锁类型
     * @param name     锁的业务名
     * @param keys     锁的标识
     */
    public RLock getLock(LockType lockType, String name, String[] keys) {
        LockInfoHandle lockInfoHandle = lockInfoHandleFactory.getLockInfoHandle(LockInfoType.SERVICE_LOCK);
        String lockName = lockInfoHandle.simpleGetLockName(name, keys);
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        return lock.getLock(lockName);
    }

    /**
     * 获得锁
     *
     * @param lockType 锁类型
     * @param lockName 锁名
     */
    public RLock getLock(LockType lockType, String lockName) {
        ServiceLocker lock = serviceLockFactory.getLock(lockType);
        return lock.getLock(lockName);
    }
}
